再重新敘述一次問題:
假設n = 878,代表說現在給你1到878個點,在沒有資訊前,你看每個點都是一座孤島,但只要倆倆孤島的編號滿足兩者的公因數z大於閾值(threshold),就代表他倆有連線。
接著就是問你在找到這878個孤島之間的連線後,我給你倆倆孤島的編號,問你我能不能從孤島4走到孤島877啊?麻煩快點告訴我謝謝。
這個回圈在做的事情就是找此時點與點之間的連線,用並查集的做法意味著:我不需要知道我要怎麼走才能從點4走到點877,我只要知道點4跟點877是都有跟同一個點連線就行,因為這樣代表他們之間也有連線,也就代表我能從點4走到點877。
for (int z = threshold + 1; 2*z <= n; z++)
for (int m = 2; m*z <= n; m++)
unionfunc(z, m*z);
有個條件
z > threshold
z就是公因數,也是開始找的孤島編號,假設n = 878,threshold = 95,代表說我要找的公因數,必須大於threshold,從96開始,也代表說孤島1~孤島95不可能有連線,因為他們沒有大於等於96的因數。
所以第一層迴圈起始條件設為這樣
z = threshold + 1
再來是終止條件。
10
= 1 x 10
= 2 x 5
= 5 x 2
= 10 x 1
像是在找10的因數時,不需要全部找完,只要找到一半,因數相乘互換的部分,就可以找到所有10的因數,而中止點恰好是10/2。所以在878個孤島中,從threshld+1的編號開始找時,只需要去找z <= 878/2的編號就行。 那因為除法比乘法慢,所以改成等價的
2*z <= n
第一層for已經幫我確認過z是大於threshold的。再來,題目說,若孤島倆倆的編號同時具有z這個因數,他們就有連線。
什麼時候會有相同的因數?z的倍數保證他一定也有z的因數,所以從編號96與編號2*96,和編號3*96..之間一定有連線。所以這裡就把孤島96和小於孤島總數的96倍數,連接起來,因此起始與終止條件設為
m = 2; m*z <= n
雖然常常感嘆他們都是怎麼想到這些解法的,但喲西喲西,又了解了一點東西。